#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>

static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t strerror_key;

#define MAX_ERROR_LEN 256

static void destructor(void *buf)
{
  free(buf);
}

static void create_key(void)
{
  int s;
  s = pthread_key_create(&strerror_key,destructor);
  if (s!=0)
    printf("pthread_key_create failed\n");
  else
    printf("pthread_key_create succeeded\n");
}

char* strerror(int err)
{
  int s;
  char *buf;

  s = pthread_once(&once,create_key);
  if (s != 0)
    printf("pthread_once failed\n");

  buf = (char*)pthread_getspecific(strerror_key);
  if (buf == NULL) {
    buf = (char*)malloc(MAX_ERROR_LEN);
    if (buf == NULL)
      printf("Failed to malloc buf\n");
    s = pthread_setspecific(strerror_key,buf);
    if (buf == NULL)
      printf("Failed to set thread specific data\n");
  }
  
  if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) {
    snprintf(buf,MAX_ERROR_LEN,"Unknown error %d",err);
  }
  else {
    strncpy(buf, _sys_errlist[err],MAX_ERROR_LEN-1);
    buf[MAX_ERROR_LEN - 1] = '\0';
  }
  return buf;
}
